from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework.parsers import MultiPartParser, FormParser
from django_filters.rest_framework import DjangoFilterBackend
from django.db.models import Count, Q, Prefetch
from django.utils import timezone
from django.core.cache import cache
from django_ratelimit.decorators import ratelimit
from django.utils.decorators import method_decorator
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from datetime import datetime, timedelta
from .models import SurveyRecord, SurveyImage, FavoriteLocation
from .serializers import (
    SurveyRecordSerializer, 
    SurveyRecordCreateSerializer, 
    SurveyImageSerializer, 
    FavoriteLocationSerializer
)
from .filters import SurveyRecordFilter, FavoriteLocationFilter
from .export_utils import SurveyExporter, FavoriteLocationExporter
from .cache_utils import (
    SurveyCacheManager, 
    FavoriteCacheManager, 
    OptimizedQueryMixin,
    get_cached_survey_stats
)

@method_decorator(ratelimit(key='user', rate='60/m', method='GET'), name='list')
@method_decorator(ratelimit(key='user', rate='30/m', method='POST'), name='create') 
@method_decorator(ratelimit(key='user', rate='30/m', method='PUT'), name='update')
@method_decorator(ratelimit(key='user', rate='30/m', method='PATCH'), name='partial_update')
@method_decorator(ratelimit(key='user', rate='10/m', method='DELETE'), name='destroy')
class SurveyRecordViewSet(OptimizedQueryMixin, viewsets.ModelViewSet):
    serializer_class = SurveyRecordSerializer
    permission_classes = [IsAuthenticated]
    filter_backends = [DjangoFilterBackend]
    filterset_class = SurveyRecordFilter
    
    # 优化查询的字段配置
    select_related_fields = ['user']
    prefetch_related_fields = ['images']
    
    def get_queryset(self):
        return SurveyRecord.objects.filter(user=self.request.user).select_related('user').prefetch_related('images')
    
    def get_serializer_class(self):
        if self.action in ['create', 'update']:
            return SurveyRecordCreateSerializer
        return SurveyRecordSerializer
    
    def list(self, request, *args, **kwargs):
        """带缓存的列表查询"""
        # 获取查询参数
        page_num = request.query_params.get('page', 1)
        search_params = {k: v for k, v in request.query_params.items() if v and k != 'page'}
        
        # 生成缓存键
        cache_key = SurveyCacheManager.get_user_surveys_cache_key(
            request.user.id, page_num, search_params
        )
        
        # 尝试从缓存获取
        cached_result = cache.get(cache_key)
        if cached_result and not search_params:  # 只有无搜索参数时使用缓存
            return Response(cached_result)
        
        # 执行查询
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            result = self.get_paginated_response(serializer.data)
            
            # 缓存结果（只缓存无搜索参数的结果）
            if not search_params:
                cache.set(cache_key, result.data, SurveyCacheManager.CACHE_TIMEOUT)
            
            return result

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)
    
    def retrieve(self, request, *args, **kwargs):
        """带缓存的详情查询"""
        survey_id = kwargs.get('pk')
        cache_key = SurveyCacheManager.get_survey_detail_cache_key(survey_id)
        
        # 尝试从缓存获取
        cached_result = cache.get(cache_key)
        if cached_result:
            return Response(cached_result)
        
        # 执行查询
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        result = serializer.data
        
        # 缓存结果
        cache.set(cache_key, result, SurveyCacheManager.CACHE_TIMEOUT)
        
        return Response(result)
    
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        instance = serializer.save()
        
        # 返回完整的记录信息
        response_serializer = SurveyRecordSerializer(instance, context={'request': request})
        return Response(response_serializer.data, status=status.HTTP_201_CREATED)
    
    @swagger_auto_schema(
        operation_description="高级搜索勘查记录",
        manual_parameters=[
            openapi.Parameter('search', openapi.IN_QUERY, description="搜索关键词", type=openapi.TYPE_STRING),
            openapi.Parameter('location_name', openapi.IN_QUERY, description="地点名称", type=openapi.TYPE_STRING),
            openapi.Parameter('address', openapi.IN_QUERY, description="地址", type=openapi.TYPE_STRING),
            openapi.Parameter('notes', openapi.IN_QUERY, description="备注", type=openapi.TYPE_STRING),
            openapi.Parameter('orientation', openapi.IN_QUERY, description="朝向", type=openapi.TYPE_STRING),
            openapi.Parameter('start_date', openapi.IN_QUERY, description="开始日期", type=openapi.TYPE_STRING, format=openapi.FORMAT_DATE),
            openapi.Parameter('end_date', openapi.IN_QUERY, description="结束日期", type=openapi.TYPE_STRING, format=openapi.FORMAT_DATE),
            openapi.Parameter('time_range', openapi.IN_QUERY, description="时间范围快捷选项", type=openapi.TYPE_STRING, 
                           enum=['today', 'week', 'month', 'quarter', 'year']),
            openapi.Parameter('center_lat', openapi.IN_QUERY, description="中心纬度", type=openapi.TYPE_NUMBER),
            openapi.Parameter('center_lng', openapi.IN_QUERY, description="中心经度", type=openapi.TYPE_NUMBER),
            openapi.Parameter('radius', openapi.IN_QUERY, description="搜索半径(km)", type=openapi.TYPE_NUMBER),
        ],
        responses={200: SurveyRecordSerializer(many=True)}
    )
    @action(detail=False, methods=['get'])
    @ratelimit(key='user', rate='100/m', method='GET')
    def search(self, request):
        """高级搜索接口"""
        queryset = self.filter_queryset(self.get_queryset())
        
        # 获取搜索参数
        search_params = {
            'search': request.query_params.get('search'),
            'location_name': request.query_params.get('location_name'),
            'address': request.query_params.get('address'),
            'notes': request.query_params.get('notes'),
            'orientation': request.query_params.get('orientation'),
            'start_date': request.query_params.get('start_date'),
            'end_date': request.query_params.get('end_date'),
            'time_range': request.query_params.get('time_range'),
            'center_lat': request.query_params.get('center_lat'),
            'center_lng': request.query_params.get('center_lng'),
            'radius': request.query_params.get('radius'),
        }
        
        # 移除空值
        search_params = {k: v for k, v in search_params.items() if v}
        
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            result = self.get_paginated_response(serializer.data)
            result.data['search_params'] = search_params
            return result

        serializer = self.get_serializer(queryset, many=True)
        return Response({
            'results': serializer.data,
            'search_params': search_params,
            'count': queryset.count()
        })
    
    @action(detail=False, methods=['get'])
    def statistics(self, request):
        """获取统计数据（带缓存）"""
        cache_key = SurveyCacheManager.get_user_stats_cache_key(request.user.id)
        
        # 尝试从缓存获取
        cached_stats = cache.get(cache_key)
        if cached_stats:
            return Response(cached_stats)
        
        # 执行统计查询
        queryset = self.get_queryset()
        now = timezone.now()
        
        # 总记录数
        total_count = queryset.count()
        
        # 本月记录数
        month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
        month_count = queryset.filter(survey_date__gte=month_start).count()
        
        # 本周记录数
        days_since_monday = now.weekday()
        week_start = (now - timedelta(days=days_since_monday)).replace(hour=0, minute=0, second=0, microsecond=0)
        week_count = queryset.filter(survey_date__gte=week_start).count()
        
        # 今日记录数
        today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
        today_count = queryset.filter(survey_date__gte=today_start).count()
        
        # 最近7天每日统计
        daily_stats = []
        for i in range(7):
            day = now - timedelta(days=i)
            day_start = day.replace(hour=0, minute=0, second=0, microsecond=0)
            day_end = day_start + timedelta(days=1)
            day_count = queryset.filter(survey_date__gte=day_start, survey_date__lt=day_end).count()
            daily_stats.append({
                'date': day.strftime('%Y-%m-%d'),
                'count': day_count
            })
        
        # 最近12个月统计
        monthly_stats = []
        for i in range(12):
            if i == 0:
                month_date = now
            else:
                if now.month > i:
                    month_date = now.replace(month=now.month - i)
                else:
                    month_date = now.replace(year=now.year - 1, month=12 - (i - now.month))
            
            month_start = month_date.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
            if month_date.month == 12:
                next_month_start = month_date.replace(year=month_date.year + 1, month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
            else:
                next_month_start = month_date.replace(month=month_date.month + 1, day=1, hour=0, minute=0, second=0, microsecond=0)
            
            month_count = queryset.filter(survey_date__gte=month_start, survey_date__lt=next_month_start).count()
            monthly_stats.append({
                'month': month_date.strftime('%Y-%m'),
                'count': month_count
            })
        
        # 朝向统计
        orientation_stats = list(
            queryset.exclude(orientation='').values('orientation')
            .annotate(count=Count('orientation'))
            .order_by('-count')[:10]
        )
        
        result = {
            'total_surveys': total_count,
            'surveys_this_month': month_count,
            'surveys_this_week': week_count,
            'surveys_today': today_count,
            'daily_surveys': daily_stats[::-1],  # 按时间正序
            'monthly_surveys': monthly_stats[::-1],  # 按时间正序
            'orientation_stats': orientation_stats,
            'latest_survey': SurveyRecordSerializer(
                queryset.order_by('-survey_date').first(), 
                context={'request': request}
            ).data if queryset.exists() else None
        }
        
        # 缓存结果
        cache.set(cache_key, result, SurveyCacheManager.CACHE_TIMEOUT)
        
        return Response(result)
    
    @action(detail=False, methods=['get'])
    def weekly_stats(self, request):
        """获取周统计数据"""
        queryset = self.get_queryset()
        now = timezone.now()
        
        # 获取本周统计
        days_since_monday = now.weekday()
        week_start = (now - timedelta(days=days_since_monday)).replace(hour=0, minute=0, second=0, microsecond=0)
        week_end = week_start + timedelta(days=7)
        
        week_surveys = queryset.filter(survey_date__gte=week_start, survey_date__lt=week_end)
        
        # 按天分组统计
        daily_data = []
        for i in range(7):
            day = week_start + timedelta(days=i)
            day_end = day + timedelta(days=1)
            day_count = week_surveys.filter(survey_date__gte=day, survey_date__lt=day_end).count()
            daily_data.append({
                'date': day.strftime('%Y-%m-%d'),
                'weekday': day.strftime('%A'),
                'count': day_count
            })
        
        return Response({
            'week_start': week_start.strftime('%Y-%m-%d'),
            'week_end': (week_end - timedelta(days=1)).strftime('%Y-%m-%d'),
            'total_count': week_surveys.count(),
            'daily_data': daily_data,
            'avg_per_day': round(week_surveys.count() / 7, 2)
        })
    
    @action(detail=False, methods=['get'])
    def monthly_stats(self, request):
        """获取月统计数据"""
        queryset = self.get_queryset()
        now = timezone.now()
        
        # 获取指定月份，默认当前月
        year = int(request.query_params.get('year', now.year))
        month = int(request.query_params.get('month', now.month))
        
        # 月份开始和结束
        month_start = timezone.datetime(year, month, 1).replace(tzinfo=now.tzinfo)
        if month == 12:
            month_end = timezone.datetime(year + 1, 1, 1).replace(tzinfo=now.tzinfo)
        else:
            month_end = timezone.datetime(year, month + 1, 1).replace(tzinfo=now.tzinfo)
        
        month_surveys = queryset.filter(survey_date__gte=month_start, survey_date__lt=month_end)
        
        # 按天分组统计
        import calendar
        days_in_month = calendar.monthrange(year, month)[1]
        daily_data = []
        
        for day in range(1, days_in_month + 1):
            day_start = timezone.datetime(year, month, day).replace(tzinfo=now.tzinfo)
            day_end = day_start + timedelta(days=1)
            day_count = month_surveys.filter(survey_date__gte=day_start, survey_date__lt=day_end).count()
            daily_data.append({
                'date': day_start.strftime('%Y-%m-%d'),
                'day': day,
                'count': day_count
            })
        
        # 按周统计
        weekly_data = []
        current_week = []
        week_count = 0
        
        for i, day_data in enumerate(daily_data):
            current_week.append(day_data)
            week_count += day_data['count']
            
            # 检查是否是周末或最后一天
            day_date = timezone.datetime.strptime(day_data['date'], '%Y-%m-%d').replace(tzinfo=now.tzinfo)
            if day_date.weekday() == 6 or i == len(daily_data) - 1:  # 周日或最后一天
                weekly_data.append({
                    'week': len(weekly_data) + 1,
                    'start_date': current_week[0]['date'],
                    'end_date': current_week[-1]['date'],
                    'count': week_count,
                    'days': current_week.copy()
                })
                current_week = []
                week_count = 0
        
        return Response({
            'year': year,
            'month': month,
            'month_name': calendar.month_name[month],
            'total_count': month_surveys.count(),
            'avg_per_day': round(month_surveys.count() / days_in_month, 2),
            'daily_data': daily_data,
            'weekly_data': weekly_data
        })
    
    @action(detail=False, methods=['get'])
    def dashboard_stats(self, request):
        """获取仪表板统计数据"""
        queryset = self.get_queryset()
        now = timezone.now()
        
        # 基础统计
        total_count = queryset.count()
        
        # 时间段统计
        today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
        today_count = queryset.filter(survey_date__gte=today_start).count()
        
        days_since_monday = now.weekday()
        week_start = (now - timedelta(days=days_since_monday)).replace(hour=0, minute=0, second=0, microsecond=0)
        week_count = queryset.filter(survey_date__gte=week_start).count()
        
        month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
        month_count = queryset.filter(survey_date__gte=month_start).count()
        
        # 最近30天趋势
        recent_trend = []
        for i in range(30):
            day = now - timedelta(days=29-i)
            day_start = day.replace(hour=0, minute=0, second=0, microsecond=0)
            day_end = day_start + timedelta(days=1)
            day_count = queryset.filter(survey_date__gte=day_start, survey_date__lt=day_end).count()
            recent_trend.append({
                'date': day.strftime('%Y-%m-%d'),
                'count': day_count
            })
        
        # 地点热力图数据（有GPS的记录）
        location_data = list(
            queryset.exclude(latitude__isnull=True, longitude__isnull=True)
            .values('latitude', 'longitude', 'location_name')
            .annotate(count=Count('id'))
        )
        
        # 常用朝向
        orientation_data = list(
            queryset.exclude(orientation='')
            .values('orientation')
            .annotate(count=Count('orientation'))
            .order_by('-count')[:8]
        )
        
        # 最新勘查记录
        latest_surveys = SurveyRecordSerializer(
            queryset.order_by('-survey_date')[:5],
            many=True,
            context={'request': request}
        ).data
        
        return Response({
            'overview': {
                'total_surveys': total_count,
                'today_surveys': today_count,
                'week_surveys': week_count,
                'month_surveys': month_count
            },
            'trend_data': recent_trend,
            'location_heatmap': location_data,
            'orientation_stats': orientation_data,
            'latest_surveys': latest_surveys,
            'summary': {
                'avg_per_day': round(total_count / max((now - queryset.order_by('survey_date').first().survey_date).days, 1), 2) if queryset.exists() else 0,
                'most_active_day': max(recent_trend, key=lambda x: x['count'])['date'] if recent_trend else None,
                'total_locations': queryset.values('location_name').distinct().count()
            }
        })
    
    @action(detail=False, methods=['get'])
    def chart_data(self, request):
        """获取图表数据"""
        queryset = self.get_queryset()
        chart_type = request.query_params.get('type', 'daily')
        
        if chart_type == 'daily':
            # 最近30天每日统计
            now = timezone.now()
            data = []
            for i in range(30):
                day = now - timedelta(days=29-i)
                day_start = day.replace(hour=0, minute=0, second=0, microsecond=0)
                day_end = day_start + timedelta(days=1)
                count = queryset.filter(survey_date__gte=day_start, survey_date__lt=day_end).count()
                data.append({
                    'date': day.strftime('%Y-%m-%d'),
                    'count': count
                })
        
        elif chart_type == 'monthly':
            # 最近12个月统计
            now = timezone.now()
            data = []
            for i in range(12):
                if i == 0:
                    month_date = now
                else:
                    if now.month > i:
                        month_date = now.replace(month=now.month - i)
                    else:
                        month_date = now.replace(year=now.year - 1, month=12 - (i - now.month))
                
                month_start = month_date.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
                if month_date.month == 12:
                    next_month_start = month_date.replace(year=month_date.year + 1, month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
                else:
                    next_month_start = month_date.replace(month=month_date.month + 1, day=1, hour=0, minute=0, second=0, microsecond=0)
                
                count = queryset.filter(survey_date__gte=month_start, survey_date__lt=next_month_start).count()
                data.append({
                    'month': month_date.strftime('%Y-%m'),
                    'count': count
                })
            data = data[::-1]  # 按时间正序
        
        elif chart_type == 'orientation':
            # 朝向分布
            data = list(
                queryset.exclude(orientation='')
                .values('orientation')
                .annotate(count=Count('orientation'))
                .order_by('-count')
            )
        
        elif chart_type == 'heatmap':
            # 地理位置热力图
            data = list(
                queryset.exclude(latitude__isnull=True, longitude__isnull=True)
                .values('latitude', 'longitude', 'location_name')
                .annotate(count=Count('id'))
            )
        
        else:
            return Response({'error': '不支持的图表类型'}, status=400)
        
        return Response({
            'chart_type': chart_type,
            'data': data
        })
    
    @action(detail=True, methods=['post'], parser_classes=[MultiPartParser, FormParser])
    def upload_image(self, request, pk=None):
        survey_record = self.get_object()
        serializer = SurveyImageSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(survey_record=survey_record)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    @action(detail=True, methods=['get'])
    def images(self, request, pk=None):
        survey_record = self.get_object()
        images = survey_record.images.all()
        serializer = SurveyImageSerializer(images, many=True)
        return Response(serializer.data)
    
    @action(detail=False, methods=['get'])
    def export_csv(self, request):
        """导出为CSV格式"""
        queryset = self.filter_queryset(self.get_queryset())
        exporter = SurveyExporter(queryset, request.user)
        return exporter.export_csv()
    
    @action(detail=False, methods=['get'])
    def export_excel(self, request):
        """导出为Excel格式"""
        queryset = self.filter_queryset(self.get_queryset())
        exporter = SurveyExporter(queryset, request.user)
        format_type = request.query_params.get('format', 'basic')
        
        if format_type == 'advanced':
            return exporter.export_excel_advanced()
        else:
            return exporter.export_excel()
    
    @action(detail=False, methods=['post'])
    def bulk_delete(self, request):
        """批量删除勘查记录"""
        ids = request.data.get('ids', [])
        if not ids:
            return Response({'error': '请提供要删除的记录ID列表'}, status=status.HTTP_400_BAD_REQUEST)
        
        queryset = self.get_queryset().filter(id__in=ids)
        count = queryset.count()
        
        if count == 0:
            return Response({'error': '未找到可删除的记录'}, status=status.HTTP_404_NOT_FOUND)
        
        # 删除关联的图片文件
        for record in queryset:
            for image in record.images.all():
                if image.image:
                    try:
                        image.image.delete(save=False)
                    except:
                        pass
        
        queryset.delete()
        return Response({'message': f'成功删除 {count} 条记录'}, status=status.HTTP_200_OK)
    
    @action(detail=False, methods=['post'])
    def bulk_update(self, request):
        """批量更新勘查记录"""
        ids = request.data.get('ids', [])
        update_data = request.data.get('data', {})
        
        if not ids:
            return Response({'error': '请提供要更新的记录ID列表'}, status=status.HTTP_400_BAD_REQUEST)
        
        if not update_data:
            return Response({'error': '请提供要更新的数据'}, status=status.HTTP_400_BAD_REQUEST)
        
        # 只允许更新特定字段
        allowed_fields = ['orientation', 'notes']
        filtered_data = {k: v for k, v in update_data.items() if k in allowed_fields}
        
        if not filtered_data:
            return Response({'error': '没有可更新的有效字段'}, status=status.HTTP_400_BAD_REQUEST)
        
        queryset = self.get_queryset().filter(id__in=ids)
        count = queryset.update(**filtered_data)
        
        if count == 0:
            return Response({'error': '未找到可更新的记录'}, status=status.HTTP_404_NOT_FOUND)
        
        return Response({'message': f'成功更新 {count} 条记录'}, status=status.HTTP_200_OK)

class SurveyImageViewSet(viewsets.ModelViewSet):
    serializer_class = SurveyImageSerializer
    permission_classes = [IsAuthenticated]
    parser_classes = [MultiPartParser, FormParser]
    
    def get_queryset(self):
        return SurveyImage.objects.filter(survey_record__user=self.request.user)

class FavoriteLocationViewSet(viewsets.ModelViewSet):
    serializer_class = FavoriteLocationSerializer
    permission_classes = [IsAuthenticated]
    filter_backends = [DjangoFilterBackend]
    filterset_class = FavoriteLocationFilter
    
    def get_queryset(self):
        return FavoriteLocation.objects.filter(user=self.request.user).order_by('-created_at')
    
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save(user=request.user)
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    
    @action(detail=False, methods=['get'])
    def autocomplete(self, request):
        """地点名称自动补全"""
        query = request.query_params.get('q', '')
        if not query:
            return Response([])
        
        # 从常用地点中搜索
        favorite_locations = self.get_queryset().filter(
            Q(name__icontains=query) | Q(address__icontains=query)
        )[:5]
        
        # 从历史记录中搜索
        survey_locations = SurveyRecord.objects.filter(
            user=request.user
        ).filter(
            Q(location_name__icontains=query) | Q(address__icontains=query)
        ).values('location_name', 'address', 'latitude', 'longitude').distinct()[:5]
        
        results = []
        
        # 添加常用地点
        for location in favorite_locations:
            results.append({
                'name': location.name,
                'address': location.address,
                'latitude': location.latitude,
                'longitude': location.longitude,
                'type': 'favorite'
            })
        
        # 添加历史地点
        for location in survey_locations:
            if len(results) < 10:  # 限制总数
                results.append({
                    'name': location['location_name'],
                    'address': location['address'],
                    'latitude': location['latitude'],
                    'longitude': location['longitude'],
                    'type': 'history'
                })
        
        return Response(results)
    
    @action(detail=False, methods=['get'])
    def export_csv(self, request):
        """导出常用地点为CSV格式"""
        queryset = self.filter_queryset(self.get_queryset())
        exporter = FavoriteLocationExporter(queryset, request.user)
        return exporter.export_csv()
    
    @action(detail=False, methods=['get'])
    def export_excel(self, request):
        """导出常用地点为Excel格式"""
        queryset = self.filter_queryset(self.get_queryset())
        exporter = FavoriteLocationExporter(queryset, request.user)
        return exporter.export_excel()
